package com.shj.em.config;

import com.shj.em.util.MD5Utils;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 *
 * @author huangjian
 *
 */
@Configuration
public class ShiroConfig {

	@Bean
	public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

		shiroFilterFactoryBean.setSecurityManager(securityManager);

		// 会把 spring.mvc.view.prefix + 此处设置的值 + spring.mvc.view.suffix 作为登陆页
		//shiroFilterFactoryBean.setLoginUrl("/login");

		// 登录成功后要跳转的链接
		//shiroFilterFactoryBean.setSuccessUrl("/index");
		// 未授权界面;
		//shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		
		//自定义拦截器
		Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
		
		//filterChain.put("kickout", value);
		shiroFilterFactoryBean.setFilters(filters);
		
		//权限控制
		// anon 表示可以匿名访问 ;  authc 表示需要登陆才可以访问
		Map<String, String> filterChainDefinition = new LinkedHashMap<String, String>();
		
		//配置不会被拦截的链接，顺序判断
		filterChainDefinition.put("/static/**", "anon");
		filterChainDefinition.put("/submitLogin", "anon");
		filterChainDefinition.put("/css/**", "anon");
		filterChainDefinition.put("/js/**", "anon");
		filterChainDefinition.put("/fonts/**", "anon");
		filterChainDefinition.put("/img/**", "anon");

        filterChainDefinition.put("/ajaxLogin", "anon");
		filterChainDefinition.put("/login", "anon");
		
		// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
		// filterChainDefinition.put("/logout", "logout");
		
		//配置shiro默认登录界面地址，前后端分离中登录界面跳转应由前端路由控制，后台仅返回json数据
		shiroFilterFactoryBean.setLoginUrl("/unauth");

		//配置所有链接均需要登陆。此句需放在最后。因为过滤链是顺序判断的，此句如果放在最上面的话，
		//后面如果有配置可以匿名访问的链接的话，将不会生效。
		filterChainDefinition.put("/**", "authc");
		
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinition);
		return shiroFilterFactoryBean;
	}

    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     * 可以扩展凭证匹配器，实现 输入密码错误次数后锁定等功能，下一次
     * @return
     */
    /*@Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(MD5Utils.HASH_ITERATIONS);//散列的次数，比如散列两次，相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }*/

    @Bean
    public AuthRealm authRealm() {
        AuthRealm myShiroRealm = new AuthRealm();
        //myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }

	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(authRealm());
		// 自定义session管理 使用redis
		securityManager.setSessionManager(sessionManager());
		// 自定义缓存实现 使用redis
		//securityManager.setCacheManager(cacheManager());
		return securityManager;
	}

	@Bean
	public SessionManager sessionManager() {
		MySessionManager mySessionManager = new MySessionManager();
		mySessionManager.setSessionDAO(sessionDAO());
		return mySessionManager;
	}

	@Bean
    public SessionDAO sessionDAO(){
	    // 暂时使用默认的内存session
	    return new MemorySessionDAO();
    }

    /*@Bean
    public AuthRealm authRealm(){
        AuthRealm authRealm = new AuthRealm();
//        authRealm.setCredentialsMatcher(credentialsMatcher);
        return authRealm;
    }*/


    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 注册全局异常处理
     * @return
     */
    /*@Bean(name = "exceptionHandler")
    public HandlerExceptionResolver handlerExceptionResolver() {
        return new MyExceptionHandler();
    }*/
}
